package cn.bandeqing.sys.rpc.impl;

import cn.bandeqing.app.entity.App;
import cn.bandeqing.app.service.IAppService;
import cn.bandeqing.authority.entity.Authority;
import cn.bandeqing.authority.service.IAuthorityService;
import cn.bandeqing.base.resp.Resp;
import cn.bandeqing.base.resp.Table;
import cn.bandeqing.city.entity.City;
import cn.bandeqing.city.service.ICityService;
import cn.bandeqing.config.entity.Config;
import cn.bandeqing.config.service.IConfigService;
import cn.bandeqing.dictList.entity.DictList;
import cn.bandeqing.dictList.service.IDictListService;
import cn.bandeqing.dictType.entity.DictType;
import cn.bandeqing.dictType.service.IDictTypeService;
import cn.bandeqing.frame.exception.CodeException;
import cn.bandeqing.order.entity.OrderStatus;
import cn.bandeqing.orderCost.entity.OcType;
import cn.bandeqing.orderDiscounts.entity.DiscountsType;
import cn.bandeqing.orderWorker.entity.OwType;
import cn.bandeqing.productInventoryRecord.entity.ChangeType;
import cn.bandeqing.productType.service.IProductTypeService;
import cn.bandeqing.role.entity.Role;
import cn.bandeqing.role.service.IRoleService;
import cn.bandeqing.roleAuthority.entity.RoleAuthority;
import cn.bandeqing.roleAuthority.service.IRoleAuthorityService;
import cn.bandeqing.store.service.IStoreService;
import cn.bandeqing.sys.req.*;
import cn.bandeqing.sys.resp.*;
import cn.bandeqing.sys.rpc.ISysRpc;
import cn.bandeqing.unipush2.service.IUnipush2Service;
import cn.bandeqing.userWalletRecord.entity.UwrType;
import cn.bandeqing.worker.entity.*;
import cn.bandeqing.workerEquipment.service.IWorkerEquipmentService;
import cn.bandeqing.workerWalletRecord.entity.AccountType;
import cn.bandeqing.workerWalletRecord.entity.WwrType;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import io.github.linpeilie.Converter;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.lang.Assert;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.bandeqing.app.entity.table.AppTableDef.APP;
import static cn.bandeqing.authority.entity.table.AuthorityTableDef.AUTHORITY;
import static cn.bandeqing.city.entity.table.CityTableDef.CITY;
import static cn.bandeqing.config.entity.table.ConfigTableDef.CONFIG;
import static cn.bandeqing.dictList.entity.table.DictListTableDef.DICT_LIST;
import static cn.bandeqing.dictType.entity.table.DictTypeTableDef.DICT_TYPE;
import static cn.bandeqing.productType.entity.table.ProductTypeTableDef.PRODUCT_TYPE;
import static cn.bandeqing.role.entity.table.RoleTableDef.ROLE;
import static cn.bandeqing.roleAuthority.entity.table.RoleAuthorityTableDef.ROLE_AUTHORITY;
import static cn.bandeqing.store.entity.table.StoreTableDef.STORE;
import static cn.bandeqing.unipush2.entity.table.Unipush2TableDef.UNIPUSH2;
import static cn.bandeqing.workerEquipment.entity.table.WorkerEquipmentTableDef.WORKER_EQUIPMENT;

@DubboService
public class SysRpcImpl implements ISysRpc {

    @Resource
    private IConfigService configService;
    @Resource
    private IRoleService roleService;
    @Resource
    private IAuthorityService authorityService;
    @Resource
    private IRoleAuthorityService roleAuthorityService;
    @Resource
    private IProductTypeService productTypeService;
    @Resource
    private IDictListService dictListService;
    @Resource
    private ICityService cityService;
    @Resource
    private IDictTypeService dictTypeService;
    @Resource
    private IStoreService storeService;
    @Resource
    private IAppService appService;
    @Resource
    private IWorkerEquipmentService workerEquipmentService;
    @Resource
    private IUnipush2Service unipush2Service;
    @Resource
    private Converter converter;

    @Override
    public Resp<Table<ConfigTable>> configTable(ConfigTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(CONFIG.CONFIG_ID.eq(req.getConfigId()))
                .where(CONFIG.CONFIG_NAME.eq(req.getConfigName()))
                .where(CONFIG.CONFIG_KEY.eq(req.getConfigKey()))
                .orderBy(CONFIG.CONFIG_ID.desc());

        Page<ConfigTable> page = configService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, ConfigTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public void configSaveOrUpdate(ConfigSaveOrUpdateReq req) {
        Config config = converter.convert(req, Config.class);
        Assert.isTrue(configService.saveOrUpdate(config), () -> new CodeException("configService.saveOrUpdate(config)"));
    }

    @Override
    public Resp<Table<RoleTable>> roleTable(RoleTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(ROLE.ROLE_ID.eq(req.getRoleId()))
                .where(ROLE.ROLE_CODE.eq(req.getRoleCode()))
                .where(ROLE.ROLE_NAME.eq(req.getRoleName()))
                .orderBy(ROLE.ROLE_ID.desc());

        Page<RoleTable> page = roleService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, RoleTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public void roleSaveOrUpdate(RoleSaveOrUpdateReq req) {
        Role role = converter.convert(req, Role.class);

        Assert.isTrue(roleService.saveOrUpdate(role), () -> new CodeException("roleService.saveOrUpdate(role)"));
    }

    @Override
    public Resp<Table<AuthorityTable>> authorityTable(AuthorityTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(AUTHORITY.AUTHORITY_ID.eq(req.getAuthorityId()))
                .where(AUTHORITY.AUTHORITY_CODE.eq(req.getAuthorityCode()))
                .where(AUTHORITY.AUTHORITY_NAME.eq(req.getAuthorityName()))
                .orderBy(AUTHORITY.AUTHORITY_ID.desc());

        Page<AuthorityTable> page = authorityService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, AuthorityTable.class);

        List<AuthorityTable> records = page.getRecords();
        Map<Long, List<AuthorityTable>> map = records.stream().collect(Collectors.groupingBy(AuthorityTable::getAuthorityPid));
        records.forEach(r -> r.setChildren(map.get(r.getAuthorityId())));

        return Resp.success(Table.of(map.get(0L), page.getTotalRow()));
    }


    @Override
    public void authoritySaveOrUpdate(AuthoritySaveOrUpdateReq req) {
        Authority authority = converter.convert(req, Authority.class);

        Assert.isTrue(authorityService.saveOrUpdate(authority), () -> new CodeException("roleService.saveOrUpdate(role)"));
    }

    @Override
    public Resp<List<RoleAuthTree>> roleAuthTree() {
        List<RoleAuthTree> roleAuthTrees = authorityService.listAs(QueryWrapper.create()
                .select(AUTHORITY.AUTHORITY_NAME.as(RoleAuthTree::getTitle),
                        AUTHORITY.AUTHORITY_ID.as(RoleAuthTree::getValue),
                        AUTHORITY.AUTHORITY_PID.as(RoleAuthTree::getPid)), RoleAuthTree.class);

        Map<Long, List<RoleAuthTree>> map = roleAuthTrees.stream().collect(Collectors.groupingBy(RoleAuthTree::getPid));
        roleAuthTrees.forEach(r -> r.setChildren(map.get(r.getValue())));

        return Resp.success(map.get(0L));
    }

    @Override
    @Transactional
    public Resp<Void> roleAuths(RoleAuthsReq req) {
        roleAuthorityService.remove(QueryCondition.create(ROLE_AUTHORITY.ROLE_ID, req.getRoleId()));
        ArrayList<RoleAuthority> roleAuths = ListUtil.of();
        req.getAuthIds().forEach(authId -> roleAuths.add(RoleAuthority.builder()
                .roleId(req.getRoleId())
                .authorityId(authId)
                .build()));
        roleAuthorityService.saveBatch(roleAuths);
        return Resp.success();
    }

    @Override
    public Resp<List<Long>> getAuths(GetAuthsReq req) {
        List<Long> auths = roleAuthorityService.listAs(QueryWrapper.create()
                .select(ROLE_AUTHORITY.AUTHORITY_ID)
                .where(ROLE_AUTHORITY.ROLE_ID.eq(req.getRoleId())), Long.class);
        return Resp.success(auths);
    }

    @Override
    public Resp<List<DictTypeSelect>> dictType(DictTypeReq req) {
        if ("productTypeSelect".equals(req.getKey())) {
            List<DictTypeSelect> dictTypeSelects = productTypeService.listAs(QueryWrapper.create()
                    .select(PRODUCT_TYPE.PT_NAME.as(DictTypeSelect::getLabel), PRODUCT_TYPE.PT_ID.as(DictTypeSelect::getValue)), DictTypeSelect.class);
            return Resp.success(dictTypeSelects);
        }
        return Resp.success();
    }

    @Override
    public Resp<List<DictResp>> dict(DictReq req) {

        switch (req.getKey()) {
            case "worker_type" -> {
                // 小哥类型
                return Resp.success(Arrays.stream(WorkerType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "worker_status" -> {
                // 小哥状态
                return Resp.success(Arrays.stream(WorkerStatus.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "worker_sex" -> {
                // 小哥性别
                return Resp.success(Arrays.stream(WorkerSex.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "worker_nation" -> {
                // 小哥民族
                return Resp.success(Arrays.stream(WorkerNation.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "worker_level" -> {
                // 小哥等级
                return Resp.success(Arrays.stream(WorkerLevel.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "order_worker_type" -> {
                // 队伍身份
                return Resp.success(Arrays.stream(OwType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "wwr_type" -> {
                // 工作人员钱包流水类型
                return Resp.success(Arrays.stream(WwrType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "uwr_type" -> {
                // 用户钱包流水类型
                return Resp.success(Arrays.stream(UwrType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "oc_type" -> {
                // 成本类型
                return Resp.success(Arrays.stream(OcType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "store_type" -> {
                List<DictResp> dictResps = storeService.listAs(QueryWrapper.create()
                        .select(STORE.STORE_NAME.as(DictResp::getLabel), STORE.STORE_ID.as(DictResp::getValue)), DictResp.class);

                // 门店
                return Resp.success(dictResps);
            }
            case "order_status" -> {
                return Resp.success(Arrays.stream(OrderStatus.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "account_type" -> {
                return Resp.success(Arrays.stream(AccountType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "change_type" -> {
                return Resp.success(Arrays.stream(ChangeType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "discounts_type" -> {
                return Resp.success(Arrays.stream(DiscountsType.values()).map(wt -> new DictResp(wt.getLabel(), wt.getValue())).toList());
            }
            case "product_type" -> {
                List<DictResp> dictResps = productTypeService.listAs(QueryWrapper.create()
                        .select(PRODUCT_TYPE.PT_NAME.as(DictResp::getLabel), PRODUCT_TYPE.PT_ID.as(DictResp::getValue))
                        .where(PRODUCT_TYPE.CUSTOMER_HIDE.eq(false))
                        .orderBy(PRODUCT_TYPE.PT_SORT.asc()), DictResp.class);

                // 套餐类型 产品类型
                return Resp.success(dictResps);
            }
        }

        List<DictResp> dictResps = dictListService.listAs(QueryWrapper.create()
                .select(DICT_LIST.DL_LABEL.as(DictResp::getLabel), DICT_LIST.DL_VALUE.as(DictResp::getValue))
                .where(DICT_LIST.DT_CODE.eq(req.getKey())), DictResp.class);
        return Resp.success(dictResps);
    }

    @Override
    public Resp<Table<CityTable>> cityTable(CityTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(CITY.CITY_ID.eq(req.getCityId()))
                .where(CITY.CITY_CODE.eq(req.getCityCode()))
                .where(CITY.CITY_NAME.eq(req.getCityName()))
                .orderBy(CITY.CITY_ID.desc());

        Page<CityTable> page = cityService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, CityTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public void citySaveOrUpdate(CitySaveOrUpdateReq req) {
        City city = converter.convert(req, City.class);

        Assert.isTrue(cityService.saveOrUpdate(city), () -> new CodeException("cityService.saveOrUpdate(city)"));
    }

    @Override
    public Resp<Map<String, List<CityResp>>> city() {
        List<CityResp> cityResps = cityService.listAs(QueryWrapper.create()
                .select(CITY.CITY_NAME.as(CityResp::getLabel),
                        CITY.CITY_CODE.as(CityResp::getValue),
                        CITY.FIRST_LETTER), CityResp.class);

        Map<String, List<CityResp>> collect = cityResps.stream().collect(Collectors.groupingBy(CityResp::getFirstLetter));

        return Resp.success(collect);
    }

    @Override
    public Resp<Table<DictTypeTable>> dictTypeTable(DictTypeTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(DICT_TYPE.DT_ID.eq(req.getDtId()))
                .where(DICT_TYPE.DT_CODE.eq(req.getDtCode()))
                .where(DICT_TYPE.DT_NAME.eq(req.getDtName()))
                .orderBy(DICT_TYPE.DT_ID.desc());

        Page<DictTypeTable> page = dictTypeService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, DictTypeTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public void dictTypeSaveOrUpdate(DictTypeSaveOrUpdateReq req) {
        DictType dt = converter.convert(req, DictType.class);

        Assert.isTrue(dictTypeService.saveOrUpdate(dt), () -> new CodeException("dictTypeService.saveOrUpdate(dt)"));
    }

    @Override
    public Resp<Table<DictListTable>> dictListTable(DictListTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(DICT_LIST.DL_ID.eq(req.getDlId()))
                .where(DICT_LIST.DL_LABEL.eq(req.getDlLabel()))
                .where(DICT_LIST.DL_VALUE.eq(req.getDlValue()))
                .where(DICT_LIST.DT_CODE.eq(req.getDtCode()))
                .orderBy(DICT_LIST.DL_ID.desc());

        Page<DictListTable> page = dictListService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, DictListTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public void dictListSaveOrUpdate(DictListSaveOrUpdateReq req) {
        DictList dl = converter.convert(req, DictList.class);

        Assert.isTrue(dictListService.saveOrUpdate(dl), () -> new CodeException("dictListService.saveOrUpdate(dl)"));
    }

    @Override
    public Resp<List<CityResp>> citySelect() {

//        String appName = DubboProviderFilter.APP_NAME.get();
//        if ("bdq-admin-api".equals(appName)) {
//            CurrentAdminUser current = StpAdminUtil.getCurrent();
//            if (current.checkStoreAccount()) {
//                List<Long> storeIds = current.getStores().stream().map(AdminUserStore::getStoreId).toList();
//                List<CityResp> cityResps = storeService.listAs(QueryWrapper.create()
//                        .select(STORE.CITY_CODE.as(CityResp::getValue),
//                                STORE.CITY_NAME.as(CityResp::getLabel))
//                        .where(STORE.STORE_ID.in(storeIds)), CityResp.class);
//                return Resp.success(cityResps);
//            }
//        }

        List<CityResp> cityResps = cityService.listAs(QueryWrapper.create()
                .select(CITY.CITY_NAME.as(CityResp::getLabel),
                        CITY.CITY_CODE.as(CityResp::getValue),
                        CITY.FIRST_LETTER), CityResp.class);

        return Resp.success(cityResps);
    }

    @Override
    public Resp<Table<AppTable>> appTable(AppTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(APP.APP_ID.eq(req.getAppId()))
                .orderBy(APP.APP_ID.desc());

        Page<AppTable> page = appService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, AppTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public void appSaveOrUpdate(AppSaveOrUpdateReq req) {
        App app = converter.convert(req, App.class);

        Assert.isTrue(appService.saveOrUpdate(app), CodeException::new);
    }

    @Override
    public Resp<AppVersionResp> appVersion(AppVersionReq req) {
        AppVersionResp av = appService.getOneAs(QueryWrapper.create()
                .where(APP.APP_PACKAGE_ID.eq(req.getAppPackageId()))
                .where(APP.APP_TYPE.eq(req.getAppType()))
                .where(APP.APP_ONLINE.eq(true))
                .orderBy(APP.APP_ID.desc())
                .limit(1), AppVersionResp.class);

        return Resp.success(av);
    }

    @Override
    public Resp<Table<EquipmentTable>> equipmentTable(EquipmentTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .orderBy(WORKER_EQUIPMENT.WORKER_EQUIPMENT_ID.desc());

        Page<EquipmentTable> page = workerEquipmentService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, EquipmentTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public Resp<Table<Unipush2Table>> unipush2Table(Unipush2TableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .orderBy(UNIPUSH2.CREATE_TIME.desc());

        Page<Unipush2Table> page = unipush2Service.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, Unipush2Table.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    public Resp<ConfigResp> keyStr(ConfigReq req) {
        if ("customer_phone".equals(req.getKey())) {
            String valStr = configService.keyStr(req.getKey(), "13288892932");
            return Resp.success(new ConfigResp(valStr));
        }
        throw new NullPointerException();
    }

}
